module WsClient

	class HandshakeResponse
		class << self
			def read(socket)
				line = read_line(socket)
				header_line = line.split(' ')
				raise HandshakeError.new("Header line too short") if header_line.length < 3
				
				version = header_line.delete_at(0)
				status = header_line.delete_at(0)
				raise HandshakeError.new("Wrong status code format") unless /\d{3}/.match(status)
				description = header_line.join(' ')
				
				headers = {}
			
				while not (line = read_line(socket)).empty? do
					pair = line.split(':', 2)
					raise HandshakeError.new("Colon used incorrectly in #{line}") if pair.length != 2
					
					name, value = pair
					value = value.gsub(/^ /, '')
					
					headers[name] = value
				end
				
				new(version, status, description, headers, socket.recv(16))
			end
			
			private
			
			def read_line(socket)
				lf = "\n"
				cr = "\r"
				
				line = []
				while (c = socket.recv(1)) != lf do
					line << c
				end
				
				c = line.delete_at(-1)
				raise HandshakeError.new("Line does not end with CRLF") unless c == cr
				
				line.join('').utf8
			end
		end
		
		attr_reader :protocol, :status_code, :description, :headers, :body
	
		def initialize(protocol, status_code, description, headers, body)
			@protocol = protocol
			@status_code = status_code.to_i
			@description = description
			@headers = WsClient::HeadersHash.new(headers)
			@body = body
		end
		
		def to_s
			response = ["#{@protocol} #{@status_code} #{@description}"]
			
			@headers.to_hash.each_pair do |name, value|
				response << "#{name}: #{value}"
			end
			
			response << "\r\n"
			response = response.join("\r\n")
			response << @body
			
			response
		end
		
		def valid?
			return false if @headers.keys.any? { |name| name.empty? }
			
			return false if @status_code != 101
			
			field = @headers['Upgrade']
			return false if field != 'WebSocket'
			
			field = @headers['Connection']
			return false if field.nil? or field.downcase != 'upgrade'
			
			true
		end
	end

end
